/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ConversePanel.java
 *
 * Created on 14 déc. 2011, 11:35:40
 */
package chatsystem.design;

import chatsystem.Controller;
import chatsystem.ListeUtilisateurs;
import chatsystem.Utilisateur;
import chatsystem.observable.FileTransfertSignal;
import chatsystem.observable.Conversation;
import chatsystem.observable.Informations;
import chatsystem.observable.ListeConversation;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.io.File;

import java.util.Observable;
import java.util.Observer;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.ListModel;

/**
 *
 * @author zoungran
 */
public class ConversePanel extends javax.swing.JPanel implements Observer {

    private Controller controller;
    private ListModel listUsers;
    private Observable fileManager;
    private ChatGUI gui;
    private ListeConversation listConvMod;
    private Informations infos;
    
    /**
     * Crée un nouveau ConversePanel
     * @param c le controler
     * @param listUsers la liste des utilisateurs qui sert de model à la JList
     * @param gui le GUI
     * @param fileManager le fileManager pour gérer les fichiers (Observer/Observable)
     */
    public ConversePanel(Controller c, ListeUtilisateurs listUsers, ChatGUI gui,
            Observable fileManager) {

        System.out.println("On entre dans le constructeur du panel conversation");
        this.controller = c;
        this.listUsers = listUsers;

        this.fileManager = fileManager;
        this.fileManager.addObserver(this);


        this.gui = gui;

        initComponents();
        this.connectedUsersList.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    int index = connectedUsersList.locationToIndex(e.getPoint());
                    setTab(index);
                    System.out.println("Double clicked on Item " + index);
                }
            }
        });
        this.listConvMod = this.controller.getListConvModel();
        this.infos = this.controller.getInfos();
        this.setModel(this.listConvMod);
        System.out.println("Fin du constructeur du panel conversation");
    }

    //Méthode initComponents() générée par l'éditeur graphique
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        disconnectButton = new javax.swing.JButton();
        sendButton = new javax.swing.JButton();
        scrolltextToSend = new javax.swing.JScrollPane();
        textToSend = new javax.swing.JTextArea();
        discussions = new javax.swing.JTabbedPane();
        scrollInfoTextArea = new javax.swing.JScrollPane();
        infoTextArea = new javax.swing.JTextArea();
        jScrollPane1 = new javax.swing.JScrollPane();
        connectedUsersList = new javax.swing.JList();
        labelConnectedUsers = new javax.swing.JLabel();
        fileButton = new javax.swing.JButton();

        disconnectButton.setText("Disconnect");
        disconnectButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                disconnectButtonActionPerformed(evt);
            }
        });

        sendButton.setText("Send");
        sendButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButtonActionPerformed(evt);
            }
        });

        textToSend.setColumns(20);
        textToSend.setRows(5);
        scrolltextToSend.setViewportView(textToSend);

        infoTextArea.setColumns(20);
        infoTextArea.setEditable(false);
        infoTextArea.setRows(5);
        infoTextArea.setText("Vous êtes connecté au ChatSystem!\n");
        scrollInfoTextArea.setViewportView(infoTextArea);

        discussions.addTab("Info", scrollInfoTextArea);

        connectedUsersList.setModel(listUsers);
        jScrollPane1.setViewportView(connectedUsersList);

        labelConnectedUsers.setText("Connected Users");

        fileButton.setText("Select File");
        fileButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(labelConnectedUsers)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGap(12, 12, 12)
                                .addComponent(disconnectButton))
                            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 146, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(fileButton)
                        .addGap(29, 29, 29)))
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(discussions, javax.swing.GroupLayout.DEFAULT_SIZE, 458, Short.MAX_VALUE)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(scrolltextToSend, javax.swing.GroupLayout.PREFERRED_SIZE, 360, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sendButton, javax.swing.GroupLayout.DEFAULT_SIZE, 92, Short.MAX_VALUE)))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(discussions, javax.swing.GroupLayout.PREFERRED_SIZE, 194, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGap(35, 35, 35)
                                .addComponent(sendButton))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(scrolltextToSend, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(labelConnectedUsers)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 203, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(disconnectButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(fileButton)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(0, 0, Short.MAX_VALUE)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 1, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(0, 0, Short.MAX_VALUE)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 0, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    /** Définit les actions à faire lorsque l'on clique sur le bouton de déconnexion*/
    private void disconnectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_disconnectButtonActionPerformed
        // Ouvre une boite de dialogue pour confirmer la déconnexion, on récupère le résultat
        int deconnecter = confirmDisconnect();
        //Si on veut se déconnecter
        if (deconnecter == 0) {
            this.controller.disconnect();
            this.infoTextArea.setText("Vous êtes connecté au ChatSystem!\n");
            removeTabs();
            gui.setConnectionWindow();
        }
        //Sinon on ne fait rien
    }//GEN-LAST:event_disconnectButtonActionPerformed

    /** Définit les actions à faire lorsque l'on clique sur le bouton de choix de fichier*/
    private void fileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileButtonActionPerformed
        // TODO add your handling code here:
        if (this.discussions.getSelectedIndex() == 0) {
            this.infoTextArea.append("Vous devez être dans un "
                    + "onglet de conversation pour envoyer un fichier !\n");
        } else {
            File file = choseFile();
            String username = this.discussions.getTitleAt(this.discussions.getSelectedIndex());
            System.out.println("Fichier choisi : " + file.getPath() + " dest: " + username);
            controller.sendFile(file, username);
        }
    }//GEN-LAST:event_fileButtonActionPerformed

    /** Définit les actions à faire lorsque l'on clique sur le bouton d'envoi de message*/
    private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendButtonActionPerformed
        // TODO add your handling code here:
        if (this.discussions.getSelectedIndex() == 0) {
            this.textToSend.setText("");
            this.infoTextArea.append("Vous devez être dans un "
                    + "onglet de conversation pour envoyer un message!\n");
        } else {
            this.controller.sendMessage(this.discussions.getTitleAt(this.discussions.getSelectedIndex()),
                    this.textToSend.getText());
            this.textToSend.setText("");
        }
    }//GEN-LAST:event_sendButtonActionPerformed


    /**
     * Fonction qui ouvre une boîte de dialogue pour demander
     * à l'utilisateur de confirmer ou non la déconnexion
     * @return choix de l'utilisateur, 0 oui, 1 non
     */
    private int confirmDisconnect() {

        int result = JOptionPane.showConfirmDialog(
                this, // fenêtre parente
                "Voulez-vous vraiment vous déconnecter ?", // corps du dialogue
                "Quitter ChatSystem?",// Titre du dialogue
                JOptionPane.YES_NO_OPTION, // type d'options
                JOptionPane.QUESTION_MESSAGE // type du dialogue
                );

        return result;
    }

    /** 
     * Ouvre une boite de dialogue pour choisir un fichier
     * seulement un fichier, il n'est pas possible de choisir un dossier
     * @return le fichier choisi
     */
    private File choseFile() {
        JFileChooser dialogue = new JFileChooser();
        //int selection = JFileChooser.APPROVE_OPTION;
        dialogue.setFileSelectionMode(JFileChooser.FILES_ONLY);
        dialogue.showOpenDialog(jPanel1);
        return dialogue.getSelectedFile();
    }
    
    private void setTab(int indexFromList) {
        String username = ((Utilisateur) listUsers.getElementAt(indexFromList)).getUserName();
        int tabIndex = this.getTabIndex(username);
        this.discussions.setEnabledAt(tabIndex, true);
    }

    /**
     * si l'utilisateur a déjà un onglet, on retourne son index
     * sinon on crée un nouvel onglet et on retourne son index
     * @param user
     * @return numéro de l'onglet
     */
    private int getTabIndex(String user) {
        //On commence à 1 car l'onglet 0 est l'onglet info, pas une conversation
        int i = 1;
        int last = this.discussions.getTabCount() - 1;

        while (i <= last && !this.discussions.getTitleAt(i).equals(user)) {
            i++;
        }

        if (i > last) {
            this.discussions.addTab(user, new JTextArea());
            this.discussions.setSelectedIndex(i);
            ((JTextArea) this.discussions.getSelectedComponent()).setEditable(false);
        }
        return i;
    }

    /**
     * Affiche un message dans une conversation
     * @param user user nom de la personne/titre de l'onglet dans lequel on va afficher le message
     * @param mess message à afficher
     */
    private void addStringToConversation(String user, String mess) {
        JTextArea tab = (JTextArea) this.discussions.getComponentAt(getTabIndex(user));
        tab.append(mess + "\n");
    }

    /**
     * Affiche un message d'erreur dans la conversation avec user
     * @param user nom de la personne/titre de l'onglet dans lequel on va afficher l'erreur
     * @param notif message d'erreur à afficher
     */
    private void displayErrorNotification(String user, String notif) {
        JTextArea tab = (JTextArea) this.discussions.getComponentAt(getTabIndex(user));
        tab.append("Error : " + notif + "\n");
    }

    /**
     * Méthode qui ajoute des informations dans la zone de texte prévue à cet effet.
     * Les infos sont : connexion et déconnexion d'utilisateurs
     * @param info Informations à faire apparaitre 
     */
    public void addInfo(String info) {
        this.infoTextArea.append(info + "\n");
    }

    /**
     * Méthode qui supprime tous les onglets de conversation
     */
    private void removeTabs() {
        for (int i = 1; i < this.discussions.getComponents().length; i++) {
            this.discussions.remove(i);
        }
    }
    

    private void setSimplePopUp(String message) {
        JOptionPane.showConfirmDialog(
                this, // fenêtre parente
                message,
                "Notification",// Titre du dialogue
                JOptionPane.DEFAULT_OPTION);
    }

    /**
     * Ouvre une boite de dialogue pour demander à l'utilisateur s'il veut
     * accepter le fichier que username lui envoie
     * @param username nom de la personne qui envoie le fichier
     * @param filename nom du fichier
     * @return 0 pour oui, 1 pour non
     */
    private int setAskingTransfertFilePopUp(String username, String filename) {
        return JOptionPane.showConfirmDialog(
                this, // fenêtre parente
                username + " veut vous envoyer le fichier "
                + filename + "\nAcceptez-vous ?", // corps du dialogue
                "Transfert de Fichier",// Titre du dialogue
                JOptionPane.YES_NO_OPTION, // type d'options
                JOptionPane.QUESTION_MESSAGE // type du dialogue
                );
    }

    
    /**
     * Méthode qui définit quoi faire au niveau du panel en fonction 
     * des signaux envoyés par les objets observés
     * @param obs : l'objet observé
     * @param arg : le signal envoyé 
     */
    public void update(Observable obs, Object arg) {
        //Si update d'une conversation
        if (arg.getClass().equals(Conversation.class)) {
        
            Conversation conv = (Conversation) arg;
            if (conv.getIsErrorMessage()) {
                this.displayErrorNotification(conv.getUserNameFromCov(), conv.getMessFromComv());
            }
            else if (conv.getIsLocalUserConv()) {
                this.addStringToConversation(conv.getUserNameFromCov(), "Me : " + conv.getMessFromComv());
            } else {
                this.addStringToConversation(conv.getUserNameFromCov(), conv.getUserNameFromCov() + " : " + conv.getMessFromComv());
            }
            
        //Si update d'information
        } else if (obs.equals(this.infos)) {
            System.out.println("On ajoute les nouvells infos.");
            this.addInfo((String) arg);
            
        //Si update pour un fichier
        } else if (obs.equals(this.fileManager)) {
            
            FileTransfertSignal sig = (FileTransfertSignal) arg;
            if (sig.getType() == FileTransfertSignal.SENDING) {
                if (sig.getState() == FileTransfertSignal.ADDED) {
                    //NOTHING
                } else if (sig.getState() == FileTransfertSignal.STARTED) {
                    if (sig.getProgress() == 0) {
                        addStringToConversation(sig.getUsername(), "The File " + sig.getFilename()
                                + " is going to be sent.");
                    } else if (sig.getProgress() == 100) {
                        addStringToConversation(sig.getUsername(), "The file " + sig.getFilename()
                                + " has been sent successfully.");
                    } else {
                        //NOTHING
                    }
                } else if (sig.getState() == FileTransfertSignal.REMOVED) {
                    addStringToConversation(sig.getUsername(), sig.getUsername() + " has refused the file "
                            + sig.getFilename());
                }
            } else {
                if (sig.getState() == FileTransfertSignal.ADDED) {
                    int reponse = setAskingTransfertFilePopUp(sig.getUsername(), sig.getFilename());
                    if (reponse == 0) {
                        controller.receiveFile(sig.getUsername());
                    } else {
                        controller.refuseFile(sig.getUsername());
                    }
                } else if (sig.getState() == FileTransfertSignal.STARTED) {
                    if (sig.getProgress() == 0) {
                        addStringToConversation(sig.getUsername(), "The File " + sig.getFilename()
                                + " is going to be downloaded.");
                    } else if (sig.getProgress() == 100) {
                        addStringToConversation(sig.getUsername(), "The file " + sig.getFilename()
                                + " has been download successfully."
                                + "\nYou can find it in " + this.controller.getDownloadPath());
                    } else {
                        //NOTHING
                    }
                } else if (sig.getState() == FileTransfertSignal.REMOVED) {
                    //NOTHING
                }
            } 
        }
    }

    /**
     * Définit cet objet comme Observer pour la liste de Conversations et les informations
     * @param model 
     */
    private void setModel(Observable model) {
        this.listConvMod = (ListeConversation) model;
        this.listConvMod.addObserver(this);
        this.infos.addObserver(this);
        this.listConvMod.notifyObservers();
    }
    
    //Variables déclarées automatiquement par l'éditeur graphique
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JList connectedUsersList;
    private javax.swing.JButton disconnectButton;
    private javax.swing.JTabbedPane discussions;
    private javax.swing.JButton fileButton;
    private javax.swing.JTextArea infoTextArea;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JLabel labelConnectedUsers;
    private javax.swing.JScrollPane scrollInfoTextArea;
    private javax.swing.JScrollPane scrolltextToSend;
    private javax.swing.JButton sendButton;
    private javax.swing.JTextArea textToSend;
    // End of variables declaration//GEN-END:variables
}
